﻿/****************************************************************************
 * 工    具：  HK_UGUIElementCustomize
 
 * 描    述： 本工具用于自定义和优化Unity项目中的UGUI元素，包含如下功能：
 *            1. 自动重命名场景中的Button、Image、Toggle、Text、Slider、Dropdown、RawImage组件，
 *            通过在组件名称前添加特定的前缀（如"Btn_"、"Img_"等）来统一命名规范，
 *            并且可以根据组件的类型和名称条件进行筛选。
 *            2. 重写了Image和Text组件的创建方法，使得新创建的Image和Text组件默认不开启RaycastTarget，
 *            有助于优化UI性能，特别是在有大量UI元素时减少不必要的射线检测。
 *
 * 版    本：  V1.0
 * 作    者：  京产肠饭
 * 
 * 创    建：  2025/01/26  V1.0
 * 
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*****************************************************************************/

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

[InitializeOnLoad]
public class HK_UGUIElementCustomize
{
    public static void ChangeState(bool isActive)
    {
        isEnabled = isActive;
    }

    static bool isEnabled = true;

    const string buttonPrefix = "Btn_";
    const string imagePrefix = "Img_";
    const string togglePrefix = "Toggle_";
    const string textPrefix = "Txt_";
    const string sliderPrefix = "Slider_";
    const string rawImagePrefix = "RawImg_";
    const string dropdownPrefix = "Dropdown_";

    static readonly HashSet<int> processedIDs = new HashSet<int>();

    static HK_UGUIElementCustomize()
    {
        EditorApplication.hierarchyChanged += OnHierarchyChanged;
    }

    static void OnHierarchyChanged()
    {
        if (!isEnabled)
            return;

        RenameComponents<Button>(buttonPrefix, go => go.name == "Button" || go.name.StartsWith("Button ("));
        RenameComponents<Image>(imagePrefix, go => go.name == "Image" || go.name.StartsWith("Image ("));
        RenameComponents<Toggle>(togglePrefix, go => go.name == "Toggle" || go.name.StartsWith("Toggle ("));
        RenameComponents<Text>(textPrefix, go =>
        {
            if (go.transform.parent != null && go.transform.parent.GetComponent<Button>() != null)
                return false;
            return go.name == "Text" || go.name.StartsWith("Text (");
        });

        RenameComponents<Slider>(sliderPrefix, go => go.name == "Slider" || go.name.StartsWith("Slider ("));

        RenameComponents<RawImage>(rawImagePrefix, go => go.name == "RawImage" || go.name.StartsWith("RawImage ("));

        RenameComponents<Dropdown>(dropdownPrefix, go => go.name == "Dropdown" || go.name.StartsWith("Dropdown ("));
    }

    static void RenameComponents<T>(string prefix, Func<GameObject, bool> condition) where T : Component
    {
        var components = UnityEngine.Object.FindObjectsOfType<T>(true);

        foreach (var component in components)
        {
            var go = component.gameObject;
            int id = go.GetInstanceID();

            if (!processedIDs.Contains(id) && EditorUtility.IsDirty(go) && condition(go))
            {
                processedIDs.Add(id);

                EditorApplication.delayCall += () =>
                {
                    if (go == null)
                        return;

                    go.name = prefix + "xxx";
                    EditorGUIUtility.PingObject(go);
                };
            }
        }
    }

    /// <summary>
    /// 重写Image组件的创建方法，创建后默认不开启RaycastTarget
    /// </summary>
    [MenuItem("GameObject/UI/HK_Image")]
    static void CreateImageModify()
    {
        if (Selection.activeGameObject != null)
        {
            Transform parent_TF = Selection.activeGameObject.transform;

            EditorApplication.ExecuteMenuItem("GameObject/UI/Image");
            Undo.SetTransformParent(Selection.activeGameObject.transform, parent_TF, "undo");
        }
        else
        {
            EditorApplication.ExecuteMenuItem("GameObject/UI/Image");
        }

        var hk_Image = Selection.activeGameObject;
        hk_Image.GetComponent<Image>().raycastTarget = false;
        hk_Image.name = "Img_xxx";
    }

    /// <summary>
    /// 重写Text组件的创建方法，创建后默认不开启RaycastTarget
    /// </summary>
    [MenuItem("GameObject/UI/HK_Text")]
    static void CreateTextModify()
    {
        if (Selection.activeGameObject != null)
        {
            Transform parent_TF = Selection.activeGameObject.transform;

#if UNITY_2021_2_OR_NEWER
            EditorApplication.ExecuteMenuItem("GameObject/UI/Legacy/Text");
#else
                EditorApplication.ExecuteMenuItem("GameObject/UI/Text");
#endif
            Undo.SetTransformParent(Selection.activeGameObject.transform, parent_TF, "undo");
        }
        else
        {
#if UNITY_2021_2_OR_NEWER
            EditorApplication.ExecuteMenuItem("GameObject/UI/Legacy/Text");
#else
                EditorApplication.ExecuteMenuItem("GameObject/UI/Text");
#endif
        }

        var hk_Text = Selection.activeGameObject;
        hk_Text.GetComponent<Text>().raycastTarget = false;
        hk_Text.name = "Txt_xxx";
    }
}
